<template>
  <x-mask v-model:visible="show">
    <template #left>
      <view class="x-select_confirm-btn" @click.stop="close">取消</view>
    </template>
    <template #right>
      <view class="x-select_confirm-btn" @click.stop="confirm">确定</view>
    </template>
    <scroll-view :scroll-y="true" class="x-select_list">
      <view
        class="x-select_item"
        v-for="item in localdata"
        :key="item[valueField]"
        @click.stop.prevent="toggleItem(item)"
      >
        <text class="x-select_item-text">{{ item[labelValue] }}</text>
        <view
          class="x-select_item-check"
          :class="
            selected.indexOf(item) !== -1 ? 'x-select_item-check-active' : ''
          "
        ></view>
      </view>
    </scroll-view>
  </x-mask>
</template>
<script setup lang="ts">
  import { ref, watch } from "vue";

  defineOptions({
    name: "x-select",
  });

  const emits = defineEmits(["confirm", "update:visible"]);

  const props = defineProps({
    localdata: {
      type: Array,
      default: [],
    },
    value: {
      type: Array,
      default: [],
    },
    multiple: {
      type: Boolean,
      default: false,
    },
    visible: {
      type: Boolean,
      default: false,
    },
    valueField: {
      type: String,
      default: "value",
    },
    labelValue: {
      type: String,
      default: "label",
    },
  });

  const show = ref(props.visible);
  watch(
    () => props.visible,
    (value) => {
      show.value = value;
    }
  );

  const selected = ref(
    props.value
      .map((item) => props.localdata.find((i) => i[props.valueField] === item))
      .filter((item) => item)
  );

  watch(
    () => props.value,
    (newVal) => {
      selected.value = newVal;
    }
  );

  const toggleItem = (item) => {
    if (props.multiple) {
      let index = selected.value.indexOf(item);
      if (index === -1) {
        selected.value.push(item);
      } else {
        selected.value.splice(index, 1);
      }
    } else {
      /**如果数组为空，去访问[0]并不会报错，只是返回undefined */
      if (selected.value[0] === item) {
        selected.value = [];
      } else {
        selected.value = [item];
      }
    }
  };

  const open = () => {
    show.value = true;
  };
  const close = () => {
    show.value = false;
    emits("update:visible", false);
    /**
     * 这里为啥要修改两个跟显示有关的值呢？
     * 因为可以通过 v-model:visible 和 ref.open 两种方式打开选择器。
     * 如果是 v-model方式，那通过 emit修改外层visible后再重入本组件内部，更新show，可以关闭
     * 但如果是只通过 open 方法打开的，那外层就不会监听 show 的变化，就将无法关闭
     */
  };
  defineExpose({
    open,
  });

  const confirm = () => {
    show.value = false;
    emits(
      "confirm",
      selected.value.map((item) => item[props.valueField])
    );
    emits("update:visible", false);
  };
</script>
<style lang="scss" scoped>
  .x-select_list {
    width: 100%;
    height: 100%;
    padding-bottom: 50rpx;
    box-sizing: border-box;
  }

  .x-select_item {
    position: relative;
    text-align: center;
    padding: 10rpx 0;
  }

  .x-select_item-text {
    font-size: 14px;
  }

  $border-color: #efefef;

  .x-select_item + .x-select_item {
    border-top: 1rpx solid $border-color;
  }

  $hightlight-blue: #007aff;

  .x-select_item-check {
    position: absolute;
    width: 20rpx;
    height: 20rpx;
    top: 50%;
    right: 20%;
    transform: translateY(-50%);
  }
  .x-select_item-check-active::after {
    position: absolute;
    content: " ";
    width: 10rpx;
    height: 20rpx;
    border-right: 1rpx solid $hightlight-blue;
    border-bottom: 1rpx solid $hightlight-blue;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%) rotate(45deg);
  }

  .x-select_confirm-btn {
    color: $hightlight-blue;
    font-size: 16px;
  }
</style>
